﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CoyoEden.Providers;
using System.ComponentModel;

namespace CoyoEden.Models
{
	/// <summary>
	/// Rate on a item(a post or a topic,or even seft-defined vote items).
	/// </summary>
	[Serializable]
	public class Rate:BusinessBase<Rate,int>
	{
		#region .ctor
		static Rate() {
			//Listent to Post's Saved event.Because a Rate sometimes can be a post
			Post.Saved += new EventHandler<SavedEventArgs>(Post_Saved);
		}
		public Rate() {
			base.Id = -1;
			_Title = "I am a Voting/Surveying/Rating Item";
			_Memo = "";
			_Memos = new Dictionary<string, object>();
			_Raters = "";
			_RaterList = new List<string>();
			_Rating = 0;
			_Hits = 0;
		}
		#endregion

		#region member variables
		private string _Title;
		public string Title {
			get { return _Title; }
			set {
				if (_Title != value) {
					MarkChanged("Title");
					_Title = value;
				}
			}
		}
		private string _Memo;
		/// <summary>
		/// Memo in in the json format
		/// </summary>
		public string Memo {
			get {
				if ((_Memos != null)&&(_Memos.Keys.Count>0)) {
					_Memo = Utils.ToStr<Dictionary<string, object>>(_Memos);
				}
				return _Memo; 
			}
			set {
				if (_Memo != value) {
					MarkChanged("Memo");
					_Memo = value;
				}
			}
		}
		private Dictionary<string, object> _Memos;
		/// <summary>
		/// Memo in the Dictionary format
		/// </summary>
		public Dictionary<string, object> Memos
		{
			get {
				if (!string.IsNullOrEmpty(_Memo)) {
					Utils.ToObject<Dictionary<string, object>>(_Memo,out _Memos);
				}
				return _Memos;
			}
			set {
				if (_Memos != value) {
					MarkChanged("Memo");
					_Memos = value;
				}
			}
		}
		private float _Rating;
		/// <summary>
		/// rating score
		/// </summary>
		public float Rating {
			get { return _Rating; }
			set {
				if (_Rating != value) {
					MarkChanged("Rating");
					_Rating = value;
				}
			}
		}
		private string _Raters;
		/// <summary>
		/// Rating people(ip).In a json format
		/// </summary>
		public string Raters {
			get {
				if ((_RaterList != null) && (_RaterList.Count > 0)) {
					_Raters = Utils.ToStr<List<string>>(_RaterList);
				}
				return _Raters;
			}
			set {
				if (_Raters != value) {
					MarkChanged("Raters");
					_Raters = value;
				}
			}
		}
		private List<string> _RaterList;
		/// <summary>
		/// Rating people(ip)
		/// </summary>
		public List<string> RaterList {
			get {
				if (!string.IsNullOrEmpty(_Raters)) {
					Utils.ToObject<List<string>>(_Raters,out _RaterList);
				}
				return _RaterList;
			}
			set { 
				if(_RaterList!=value){
					MarkChanged("Raters");
					_RaterList = value;
				}
			}
		}
		private int _Hits;
		/// <summary>
		/// Rating people's number
		/// </summary>
		public int Hits{
			get { return _Hits; }
			set {
				if (_Hits != value) {
					MarkChanged("Hits");
					_Hits = value;
				}
			}
		}
		/// <summary>
		/// Rate's related post
		/// </summary>
		public Post RelatedPost {
			get {
				if (Memos.Keys.Contains("PostID")) {
					var postid = Convert.ToInt32(_Memos["PostID"]);
					return Post.GetPost(postid);
				}
				return null;
			}
		}
		private static object _SyncRoot = new object();
		private static List<Rate> _Rates;
		/// <summary>
		/// A sorted collection of all posts in the blog.
		/// Sorted by date.
		/// </summary>
		public static List<Rate> Rates
		{
			get
			{
				if (_Rates == null)
				{
					lock (_SyncRoot)
					{
						if (_Rates == null)
						{
							_Rates = PortalService.FillRates();
							_Rates.TrimExcess();
						}
					}
				}

				return _Rates;
			}
		}
		#endregion

		#region businessbase
		protected override void ValidationRules()
		{
			AddRule("Title", "标题非法[标题为空或者标题已经存在]", TitleRule());
		}

		protected override Rate DataSelect(int id)
		{
			return PortalService.SelectRate(id);
		}

		protected override void DataUpdate()
		{
			if (IsChanged) PortalService.UpdateRate(this);
		}

		protected override void DataInsert()
		{
			if (IsNew) PortalService.InsertRate(this);
		}

		protected override void DataDelete()
		{
			if (IsDeleted) PortalService.DeleteRate(this);
		}
		#endregion

		#region business rules
		private bool TitleRule() {
			var isBroken = false;
			if (string.IsNullOrEmpty(Title))
			{
				isBroken = true;
			}
			else {
				var item = Rates.Find(obj=>(obj.Title.ToLowerInvariant()==Title.ToLowerInvariant())&&(obj.Id!=this.Id));
				if (item != null) isBroken = true;
			}
			return isBroken;
		}
		#endregion

		#region Events
		/// <summary>
		/// Occurs before rates are being updated batchly.
		/// </summary>
		public static event EventHandler<CancelEventArgs> BatchUpdatingRates;
		/// <summary>
		/// Raises the event in a safe way
		/// </summary>
		protected static void OnBatchUpdatingRates(List<Rate> items, CancelEventArgs e)
		{
			if (BatchUpdatingRates != null)
			{
				BatchUpdatingRates(items, e);
			}
		}

		/// <summary>
		/// Occurs when rates have been updated
		/// </summary>
		public static event EventHandler<EventArgs> RatesBatchUpdated;
		/// <summary>
		/// Raises the event in a safe way
		/// </summary>
		protected static void OnRatesBatchUpdated(List<Rate> items)
		{
			if (RatesBatchUpdated != null)
			{
				RatesBatchUpdated(items, new EventArgs());
			}
		}
		#endregion

		#region Event handlers
		static void Post_Saved(object sender, SavedEventArgs e)
		{
			if (e.Action == SaveAction.Insert || e.Action == SaveAction.None) return;

			Post post = sender as Post;
			var relatedRates = Rate.Rates.FindAll(item => {
				if ((item.Memos != null) && item.Memos.Keys.Contains("PostID")) {
					if (item.Memos["PostID"].ToString() == post.Id.ToString())
					{
						return true;
					}
					return false;
				} else {
					return false;
				}
			});
			if (relatedRates == null||relatedRates.Count==0) return;

			if (e.Action == SaveAction.Delete) {
				DeleteRates(relatedRates);
				return;
			}

			//The post has been updated
			relatedRates.ForEach(obj => {
				Rates.Remove(obj);
				obj.Title = post.Title;
				obj.Memos["PostUrl"] = post.PermaLink.ToString();
				Rates.Add(obj);
			});
			UpdateRates(relatedRates);
		}
		#endregion

		#region Methods
		/// <summary>
		/// insert a rate collection
		/// </summary>
		/// <param name="items"></param>
		public static void InsertRates(List<Rate> items){
			//only insert new rates
			items=items.FindAll(obj=>obj.IsNew);
			PortalService.InsertRates(items);
		}
		/// <summary>
		/// update a rate collection
		/// </summary>
		/// <param name="items"></param>
		public static void UpdateRates(List<Rate> items) {
			CancelEventArgs e = new CancelEventArgs();
			OnBatchUpdatingRates(items, e);
			OnBatchUpdatingRates(items, e);
			if (!e.Cancel)
			{
				PortalService.UpdateRates(items);
				OnRatesBatchUpdated(items);
			}
		}
		/// <summary>
		/// get a rate
		/// </summary>
		/// <param name="id"></param>
		/// <returns></returns>
		public static Rate GetRate(int id) {
			return Rate.Rates.Find(obj=>obj.Id==id);
		}
		/// <summary>
		/// force to delete a rate,and don't raise extension events
		/// </summary>
		public void ForceDelete() {
			PortalService.DeleteRate(this);
		}
		/// <summary>
		/// batch delete rates
		/// </summary>
		/// <param name="items"></param>
		public static void DeleteRates(List<Rate> items) {
			CancelEventArgs e = new CancelEventArgs();
			OnBatchUpdatingRates(items, e);
			if (!e.Cancel)
			{
				PortalService.DeleteRates(items);
				items.ForEach(obj=>Rates.Remove(obj));
				OnRatesBatchUpdated(items);
			}
		}
		#endregion
	}
}
